﻿#pragma once

#include <map>
#include <memory>
#include <sstream>
#include <stdexcept>
#include <string>
#include <variant>
#include <vector>

namespace xi
{

namespace utils
{

namespace details
{

class JsonParse;

} // namespace details

class Json
{
    friend class details::JsonParse;
    using has_dump_json =
        decltype([](auto &&x) -> decltype(x.dump_json(), std::true_type{}) { return std::true_type{}; });
    using has_dump_json_pointer =
        decltype([](auto &&x) -> decltype(x->dump_json(), std::true_type{}) { return std::true_type{}; });

  public:
    enum Type
    {
        Null,
        Bool,
        Int,
        Double,
        String,
        Array,
        Object
    };

  private:
    /**
     * @brief 提取类型
     *
     * @tparam T
     * @return constexpr Type
     */
    template <typename T> static constexpr Type _type(T) noexcept
    {
        if constexpr (std::is_same_v<T, bool>)
            return Bool;
        else if constexpr (std::is_integral_v<T>)
            return Int;
        else if constexpr (std::is_floating_point_v<T>)
            return Double;
        else if constexpr (std::is_convertible_v<T, std::string>)
            return String;
        else if constexpr (std::is_same_v<T, std::vector<Json>>)
            return Array;
        else if constexpr (std::is_same_v<T, std::map<std::string, Json>>)
            return Object;
        else
            return Null;
    }

  public:
    /**
     * @brief 默认构造函数
     *
     */
    explicit Json() : Json(std::monostate{})
    {
    }

    /**
     * @brief 类型构造
     *
     * @tparam T
     * @param[in] value
     */
    template <typename T>
        requires(std::is_convertible_v<T, decltype(std::declval<Json>().m_value)>)
    Json(const T &value) : m_type(_type(value)), m_value(value)
    {
    }

    /**
     * @brief 具有序列化的类型构造
     *
     * @tparam T
     */
    template <typename T>
        requires(decltype(std::declval<has_dump_json>()(std::declval<T>()))::value)
    Json(const T &value) : Json(value.dump_json())
    {
    }

    /**
     * @brief 具有序列化的指针类型构造
     *
     * @tparam T
     */
    template <typename T>
        requires(decltype(std::declval<has_dump_json_pointer>()(std::declval<T>()))::value)
    Json(const T &value) : Json(value->dump_json())
    {
    }

    /**
     * @brief 向量构造
     *
     * @tparam T
     * @param[in] value
     */
    template <typename T> Json(const std::vector<T> &value)
    {
        for (const auto &v : value)
            append(v);
    }

    /**
     * @brief 移动构造
     *
     * @param[in] other
     */
    Json(Json &&other) : m_type(other.m_type), m_value(std::move(other.m_value))
    {
    }

    /**
     * @brief 移动赋值
     *
     * @param[in] other
     * @return Json&
     */
    Json &operator=(Json &&other)
    {
        if (this != &other) [[likely]]
        {
            m_type = std::move(other.m_type);
            m_value = std::move(other.m_value);
        }
        return *this;
    }

    Json(const Json &) = delete;
    Json &operator=(const Json &) = delete;

    /**
     * @brief 显式类型转换
     *
     * @tparam
     * @return T
     */
    template <typename T> T as(T = T{}) const
    {
        if (m_type != _type(T{}))
            throw std::logic_error("Type error: not the same type");
        return std::get<T>(m_value);
    }

    /**
     * @brief 获得类型
     *
     * @return Type
     */
    constexpr Type type() const noexcept
    {
        return m_type;
    }

    /**
     * @brief 索引
     *
     * @param[in] index
     * @return Json &
     */
    Json &operator[](std::size_t index)
    {
        if (m_type != Array)
        {
            m_type = Array;
            m_value = std::vector<Json>{};
        }

        auto &arr = std::get<std::vector<Json>>(m_value);
        std::size_t size = arr.size();
        if (index >= size)
            arr.resize(index + 1);
        return arr[index];
    }

    /**
     * @brief 键值
     *
     * @param[in] key
     * @return Json &
     */
    Json &operator[](const std::string &key)
    {
        if (m_type != Object)
        {
            m_type = Object;
            m_value = std::map<std::string, Json>{};
        }

        return std::get<std::map<std::string, Json>>(m_value)[key];
    }

    /**
     * @brief 数组迭代器
     *
     * @return std::vector<Json>::iterator
     */
    std::vector<Json>::iterator begin()
    {
        if (m_type != Array)
            throw std::logic_error("Type error: not an array");
        return std::get<std::vector<Json>>(m_value).begin();
    }

    /**
     * @brief 数组迭代器
     *
     * @return std::vector<Json>::iterator
     */
    std::vector<Json>::iterator end()
    {
        if (m_type != Array)
            throw std::logic_error("Type error: not an array");
        return std::get<std::vector<Json>>(m_value).end();
    }

    /**
     * @brief 包含索引
     *
     * @param[in] index
     * @return true
     * @return false
     */
    bool contains(std::size_t index) const
    {
        if (m_type != Array)
            return false;
        return index < std::get<std::vector<Json>>(m_value).size();
    }

    /**
     * @brief 包含键
     *
     * @param[in] key
     * @return auto
     */
    bool contains(const std::string &key) const
    {
        if (m_type != Object)
            return false;
        auto &obj = std::get<std::map<std::string, Json>>(m_value);
        return obj.find(key) != obj.end();
    }

    /**
     * @brief 移除索引
     *
     * @param[in] index
     */
    void remove(std::size_t index)
    {
        if (contains(index))
        {
            auto &arr = std::get<std::vector<Json>>(m_value);
            arr.erase(arr.begin() + index);
        }
    }

    /**
     * @brief 移除键
     *
     * @param[in] key
     */
    void remove(const std::string &key)
    {
        auto &obj = std::get<std::map<std::string, Json>>(m_value);
        obj.erase(key);
    }

    /**
     * @brief 附加元素
     *
     * @param[in] other
     */
    void append(Json &&other)
    {
        if (m_type != Array)
        {
            m_type = Array;
            m_value = std::vector<Json>{};
        }
        std::get<std::vector<Json>>(m_value).push_back(std::move(other));
    }

    /**
     * @brief 序列化
     *
     * @return std::string
     */
    std::string dump() const
    {
        std::stringstream ss;
        switch (m_type)
        {
        case Null:
            ss << "null";
            break;
        case Bool:
            ss << (std::get<bool>(m_value) ? "true" : "false");
            break;
        case Int:
            ss << std::to_string(std::get<int>(m_value));
            break;
        case Double:
            ss << std::to_string(std::get<double>(m_value));
            break;
        case String:
            ss << "\"" + std::get<std::string>(m_value) + "\"";
            break;
        case Array: {
            auto &arr = std::get<std::vector<Json>>(m_value);
            std::string result = "[";
            for (std::size_t i = 0; i < arr.size(); ++i)
            {
                if (i > 0)
                    result += ", ";
                result += arr[i].dump();
            }
            result += "]";
            ss << result;
            break;
        }
        case Object: {
            auto &obj = std::get<std::map<std::string, Json>>(m_value);
            std::string result = "{";
            for (auto it = obj.begin(); it != obj.end(); ++it)
            {
                if (it != obj.begin())
                    result += ", ";
                result += "\"" + it->first + "\": " + it->second.dump();
            }
            result += "}";
            ss << result;
            break;
        }
        }
        return ss.str();
    }

  private:
    Type m_type;
    std::variant<std::monostate, bool, int, double, std::string, std::vector<Json>, std::map<std::string, Json>>
        m_value;
};

namespace details
{

class JsonParse
{
  public:
    /**
     * @brief 默认构造
     *
     */
    explicit JsonParse() : m_str(""), m_idx(0)
    {
    }

    /**
     * @brief 载入字符串
     *
     * @param[in] str
     */
    void load(std::string &&str)
    {
        m_str = std::move(str);
        m_idx = 0;
    }

    /**
     * @brief 解析字符串
     *
     * @return Json
     */
    Json analyze()
    {
        skip_whitespace();
        char c = m_str[m_idx];
        switch (c)
        {
        case 'n':
            return parse_null();
        case 't':
            return parse_bool();
        case 'f':
            return parse_bool();
        case '0':
        case '1':
        case '2':
        case '3':
        case '4':
        case '5':
        case '6':
        case '7':
        case '8':
        case '9':
        case '-':
            return parse_number();
        case '\"':
            return parse_string();
        case '[':
            return parse_array();
        case '{':
            return parse_object();
        case '\0':
            throw std::logic_error("Parse error: unexpected end of input");
        default:
            throw std::logic_error("Invalid JSON");
        }
        return Json{};
    }

  private:
    void skip_whitespace()
    {
        while (m_str[m_idx] == ' ' || m_str[m_idx] == '\t' || m_str[m_idx] == '\n' || m_str[m_idx] == '\r')
            m_idx++;
    }

    Json parse_null()
    {
        if (m_str.compare(m_idx, 4, "null") == 0)
        {
            m_idx += 4;
            return Json{};
        }
        throw std::logic_error("Parse error: null expected");
        return Json{};
    }

    Json parse_bool()
    {
        if (m_str.compare(m_idx, 4, "true") == 0)
        {
            m_idx += 4;
            return Json(true);
        }
        if (m_str.compare(m_idx, 5, "false") == 0)
        {
            m_idx += 5;
            return Json(false);
        }
        throw std::logic_error("Parse error: boolean expected");
        return Json{};
    }

    Json parse_number()
    {
        int pos = m_idx;
        if (m_str[m_idx] == '-')
            m_idx++;

        if (m_str[m_idx] < '0' || m_str[m_idx] > '9')
            throw std::logic_error("Parse error: number expected");
        while (m_str[m_idx] >= '0' && m_str[m_idx] <= '9')
            m_idx++;

        if (m_str[m_idx] != '.')
        {
            // 利用 atoi 会转换直到遇到非数字字符的特性，直接解析后面所有字符
            int i = std::atoi(m_str.c_str() + pos);
            return Json(i);
        }

        m_idx++;

        if (m_str[m_idx] < '0' || m_str[m_idx] > '9')
            throw std::logic_error("Parse error: number expected");
        while (m_str[m_idx] >= '0' && m_str[m_idx] <= '9')
            m_idx++;

        double d = std::atof(m_str.c_str() + pos);
        return Json(d);
    }

    Json parse_string()
    {
        std::string str;
        while (m_str[++m_idx] != '\"')
        {
            if (m_str[m_idx] == '\\')
            {
                switch (m_str[++m_idx])
                {
                case '\"':
                    str += '\"';
                    break;
                case '\\':
                    str += '\\';
                    break;
                case '/':
                    str += '/';
                    break;
                case 'b':
                    str += '\b';
                    break;
                case 'f':
                    str += '\f';
                    break;
                case 'n':
                    str += '\n';
                    break;
                case 'r':
                    str += '\r';
                    break;
                case 't':
                    str += '\t';
                    break;
                case 'u':
                    // unicode
                    break;
                default:
                    throw std::logic_error("Parse error: invalid escape character");
                }
            }
            else
                str += m_str[m_idx];
        }
        m_idx++;
        return Json(str);
    }

    Json parse_array()
    {
        auto arr = Json{};
        while (m_str[++m_idx] != ']')
        {
            // 直接递归解析
            arr.append(analyze());
            skip_whitespace();
            if (m_str[m_idx] == ']')
                break;
            if (m_str[m_idx] != ',')
                throw std::logic_error("Parse error: comma expected");
        }
        m_idx++;
        return arr;
    }

    Json parse_object()
    {
        auto obj = Json{};
        while (m_str[++m_idx] != '}')
        {
            // 解析 key
            std::string key = analyze().as<std::string>();
            skip_whitespace();

            // 解析 value
            if (m_str[m_idx++] != ':')
                throw std::logic_error("Parse error: colon expected");

            // 添加到对象中
            obj[key] = analyze();
            skip_whitespace();
            if (m_str[m_idx] == '}')
                break;
            if (m_str[m_idx] != ',')
                throw std::logic_error("Parse error: comma expected");
        }
        m_idx++;
        return obj;
    }

  private:
    std::string m_str; // 原始字符串
    int m_idx;         // 下一个解析位置
};

} // namespace details

/**
 * @brief 解析字符串
 *
 * @param[in] str
 * @return Json
 */
inline Json parse(std::string &&str)
{
    details::JsonParse jp;
    jp.load(std::move(str));
    return jp.analyze();
}

} // namespace utils

} // namespace xi
